//
// Created by LiuYou on 2021/5/1.
//

#define _GNU_SOURCE 1

#include <cstring>
#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cassert>
#include <unistd.h>
#include <sys/poll.h>
#include <fcntl.h>


int main(int argc, char** argv) {
//    std::cout << "argv[0]: " << argv[0] << std::endl;
//    std::cout << "basename(argv[0]): " << basename(argv[0]) << std::endl;
//    std::cout << "dirname(argv[0]): " << dirname(argv[0]) << std::endl;

    if (argc <= 2) {
        std::cout << "usage: " << basename(argv[0]) << " IpAddress PortNumber" << std::endl;
        return 1;
    }
    const char* ip = argv[1];
    int port = std::atoi(argv[2]);
//    int port = std::strtol(argv[2], );

    sockaddr_in serverSockAddrIn{
            .sin_family=PF_INET,
            .sin_port=htons(port),
            {.s_addr=0}
    };
    inet_pton(AF_INET, ip, &serverSockAddrIn.sin_addr);

    int sockFD = socket(PF_INET, SOCK_STREAM, 0);
    assert(sockFD >= 0);
    if (connect(sockFD, (sockaddr*) &serverSockAddrIn, sizeof(serverSockAddrIn)) < 0) {
        std::cout << "connection failed" << std::endl;
        close(sockFD);
        return 1;
    }
    pollfd pollFDS[2]{
            {.fd=0, .events=POLLIN, .revents=0},
            {.fd=sockFD, .events=POLLIN | POLLRDHUP, .revents=0}
    };

    constexpr int BUFFER_SIZE = 64;
    char readBuffer[BUFFER_SIZE];
    int pipeFD[2];
    int ret = pipe(pipeFD);
    assert(ret != -1);
    for (;;) {
        ret = poll(pollFDS, 2, -1);
        if (ret < 0) {
            std::printf("poll failure\n");
            break;
        }
        if (pollFDS[1].revents & POLLRDHUP) {
            std::printf("server close the connection\n");
            break;
        } else if (pollFDS[1].revents & POLLIN) {
            std::memset(readBuffer, '\0', BUFFER_SIZE);
            recv(pollFDS[1].fd, readBuffer, BUFFER_SIZE - 1, 0);
            std::printf("%s\n", readBuffer);
        }
        if (pollFDS[0].revents & POLLIN) {
            // 使用splice将用户输入的数据直接写到sockFD上(零拷贝)
            ret = splice(0, NULL, pipeFD[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
            ret = splice(pipeFD[0], NULL, sockFD, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
        }
    }
    close(sockFD);


    return 0;
}



































////
//// Created by LiuYou on 2021/5/1.
////
//#define _GNU_SOURCE 1
//
//#include <iostream>
//#include <libgen.h>
////#include <cygwin/in.h>
//#include <arpa/inet.h>
//#include <cassert>
//#include <sys/unistd.h>
//#include <sys/poll.h>
//#include <cstring>
//// TODO # error "Never use <bits/fcntl.h> directly; include <fcntl.h> instead."
////#include <bits/fcntl.h>
//#include <fcntl.h>
//
//int main(int argc, char **argv) {
////    std::cout << "argv[0]: " << argv[0] << std::endl;
////    std::cout << "basename(argv[0]): " << basename(argv[0]) << std::endl;
////    std::cout << "dirname(argv[0]): " << dirname(argv[0]) << std::endl;
//
//    if (argc <= 2) {
//        std::cout << "usage: " << basename(argv[0]) << " IpAddress PortNumber" << std::endl;
//        return 1;
//    }
//    const char *ip = argv[1];
//    int port = std::atoi(argv[2]);
////    int port = std::strtol(argv[2], );
//
//    sockaddr_in serverSockAddrIn{
//            .sin_family=PF_INET,
//            .sin_port=htons(port),
//            {.s_addr=0}
//    };
//    inet_pton(AF_INET, ip, &serverSockAddrIn.sin_addr);
//
//    int sockFD = socket(PF_INET, SOCK_STREAM, 0);
//    assert(sockFD >= 0);
//    if (connect(sockFD, (sockaddr *) &serverSockAddrIn, sizeof(serverSockAddrIn)) < 0) {
//        std::cout << "connection failed" << std::endl;
//        close(sockFD);
//        return 1;
//    }
//    pollfd pollFDS[2]{
//            {.fd=0, .events=POLLIN, .revents=0},
//            {.fd=sockFD, .events=POLLIN | POLLRDHUP, .revents=0}
//    };
//
//    constexpr int BUFFER_SIZE = 64;
//    char readBuffer[BUFFER_SIZE];
//    int pipeFD[2];
//    int ret = pipe(pipeFD);
//    assert(ret != -1);
//    for (;;) {
//        ret = poll(pollFDS, 2, -1);
//        if (ret < 0) {
//            std::printf("poll failure\n");
//            break;
//        }
//        if (pollFDS[1].revents & POLLRDHUP) {
//            std::printf("server close the connection\n");
//            break;
//        } else if (pollFDS[1].revents & POLLIN) {
//            std::memset(readBuffer, '\0', BUFFER_SIZE);
//            recv(pollFDS[1].fd, readBuffer, BUFFER_SIZE - 1, 0);
//            std::printf("%s\n", readBuffer);
//        }
//        if (pollFDS[0].revents & POLLIN) {
//            // 使用splice将用户输入的数据直接写到sockFD上(零拷贝)
//            ret = splice(0, NULL, pipeFD[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
//            ret = splice(pipeFD[0], NULL, sockFD, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
//        }
//    }
//    close(sockFD);
//
//
//    return 0;
//}